#include <QBuffer>
#include <QByteArray>
#include <QDateTime>
#include <QPixmap>

#include <QtCrypto>

#include "centry.h"
#include "src/constants.h"

CEntry::CEntry(CDatabase &db, QString id):
        m_db(db), m_id(id)
{

}

CEntry::~CEntry()
{
    qDeleteAll(m_fields);
}

int CEntry::columnCount(bool all)
{
#ifdef IS_MOBILE
    if(!all)
        return 2;
#endif
    if(!all) // because there was a warning :)
        return 5;
    return 5;
}

QVariant CEntry::getData(int col, bool show)
{
    if(!fill())
    {
        debug("Can't get data");
        return QVariant();
    }

    if(col==this->Login || col==this->Password)
    {
        if(show)
        {
            #ifdef IS_MOBILE
                return m_data.value(getStringById(col));
            #else
                QByteArray b = CDatabase::decrypt_array(m_data.value(getStringById(col)).toByteArray());
                return QString::fromUtf8(b);
            #endif
        }
        else
            return QString(10, '*');
    }

    if(col==this->Name || col==this->Comments)
        return QString::fromUtf8(m_data.value(getStringById(col)).toByteArray());

     return m_data.value(getStringById(col));
}

QVariant CEntry::getDecoration(int col)
{
    if(!fill())
    {
        debug("Can't get data");
        return QVariant();
    }

    if(col==Name)
    {
        return m_data.value(getStringById(this->Icon));
    }
    return QVariant();
}

bool CEntry::fill()
{
    if(m_data.count())
        return true;

    m_data = m_db.getEntry(m_id);

    foreach(QString id, m_data.keys())
    {
        if(id==getStringById(this->Login) || id==getStringById(this->Password))
        {
            #ifndef IS_MOBILE
                m_data.insert(id, m_data.value(id));
            #else
                m_data.insert(id, CDatabase::decrypt_array(m_data.value(id).toByteArray()));
            #endif
        }
        else if(id==getStringById(this->Name) || id==getStringById(this->Comments))
        {
            m_data.insert(id, CDatabase::decrypt_array(m_data.value(id).toByteArray()));
        }
        else if(id==getStringById(this->Icon))
        {
            QByteArray buffer = CDatabase::decrypt_array(m_data.value(id).toByteArray());

            m_data.remove(id);

            QPixmap pix;
            pix.loadFromData(buffer);
            if(!pix.isNull())
            {
                m_data.insert(id, pix);
                m_data.insert(id + "_id", QString());
            }
            else // if can't load stored image, let's try to load by id
                if(m_data.contains(id + "_id") && !m_data.value(id + "_id").isNull())
                {
                    QPixmap pix(":/icons/" + m_data.value(id + "_id").toString());
                    if(!pix.isNull())
                        m_data.insert(id, pix);
                }

            if(m_data.value(id).isNull()) // if anyway is null
            {
                    //debug("Inserting default image for id: " + id);
                    m_data.insert(id, QPixmap(":/icons/entry_default"));
                    m_data.insert(id + "_id", "entry_default");
            }
        }
        else if(id==getStringById(this->Creation) || id==getStringById(this->Access) || id==getStringById(this->Modifyed))
        {
            QDateTime daytime = QDateTime::fromString(m_data.value(id).toString(), Qt::ISODate);
            m_data.remove(id);
            m_data.insert(id, daytime);
        }
        else if(id==getStringById(this->Parent))
        {
            //int parent_id = m_data.value(id).toInt();
            //m_data.remove(id);
            //m_data.insert(id, m_db.getCathegoryName(parent_id));
        }
    }

    return m_data.count();
}

QString CEntry::getStringById(int id)
{
    switch(id)
    {
        case Name: return "name";
        case Parent: return "parent";
//        case Image: return "image";
        case Icon: return "icon";
        case Creation: return "creation";
        case Access: return "access";
        case Modifyed: return "modifyed";
//        case Expiration: return "expiration";
        case Comments: return "comments";
        case Login: return "login";
        case Password: return "password";
        case IconId: return "icon_id";
        case Id: return "id";
    }

    return QString();
}

QString CEntry::getFieldName(int id)
{
    switch(id)
    {
        case Name: return tr("Name");
        case Parent: return tr("Parent");
 //       case Image: return tr("Image");
        case Icon: return tr("Icon");
        case Creation: return tr("Date creation");
        case Access: return tr("Date access");
        case Modifyed: return tr("Date modifyed");
//        case Expiration: return tr("Date expiration");
        case Comments:  return tr("Comments");
        case Login: return tr("Login");
        case Password: return tr("Password");
        case IconId: return tr("Icon id");
        case Id: return tr("ID");
    }

    return QString();
}

int CEntry::receiveFields()
{
    qDeleteAll(m_fields);
    m_fields.clear();

    QList<QMap<QString, QVariant> > fields = m_db.getEntryFields(m_id);

    QList<CEntryFieldPointer> list;

    int count = fields.count();
    for(int i=0; i<count; i++)
    {
        CEntryField *f = new CEntryField;
        QVariant data;

        QMap<QString, QVariant> &map = fields[i];
        foreach(QString key, map.keys())
        {
            if(key=="entry_id")
                continue;
            else if(key=="id")
                f->id = map.value(key).toString();
            else if(key=="name")
                f->setName(map.value(key).toByteArray());
            else if(key=="type")
                f->type = map.value(key).toInt();
            else if(key=="value")
                data = map.value(key);
            else if(key=="order")
                f->order = map.value(key).toInt();
        }

        f->setValue(data);

        list.append(f);
    }

    qSort(list);

    m_fields.clear();

    for(int i=list.count()-1; i>=0; i--)
        m_fields.append(list.at(i).e);

    return m_fields.count();
}

QList<CEntryField*> CEntry::getFields()
{
    if(!m_fields.count())
        receiveFields();

    return m_fields;
}

CEntryField* CEntry::getField(int id)
{
    if(!m_fields.count())
        receiveFields();

    return m_fields.at(id);
}

int CEntry::fieldsCount()
{
    if(!m_fields.count())
        receiveFields();

    return m_fields.count();
}

bool CEntry::haveCustomIcon()
{
    return m_data.value("icon_id").isNull();
}

QString CEntryField::name()
{
    #ifdef IS_MOBILE
        return QString::fromUtf8(m_name);
    #else
        return QString::fromUtf8(CDatabase::decrypt_array(m_name));
    #endif
}

void CEntryField::setName(const QByteArray &b)
{
    #ifndef IS_MOBILE
        m_name = b;
    #else
        m_name = CDatabase::decrypt_array(b);
    #endif
}

void CEntryField::setValue(const QVariant &v)
{
    #ifndef IS_MOBILE
        m_value = v;
    #else
        QByteArray decrypt = CDatabase::decrypt_array(v.toByteArray());

        if(type == CEntryField::Image)
        {
                QPixmap pix;
                pix.loadFromData(decrypt);

                if(!pix.isNull())
                {
                    QByteArray tmp;

                    QBuffer buf(&tmp);
                    buf.open(QIODevice::WriteOnly);

                    pix.save(&buf, "PNG");
                    buf.close();

                    m_value = tmp;
                }
                else
                {
                    m_value =  decrypt;
                }
        }
        else
        {
            m_value =  decrypt;
        }
    #endif
}

QVariant CEntryField::value()
{
    #ifdef IS_MOBILE
        return m_value;
    #else
        QByteArray decrypt = CDatabase::decrypt_array(m_value.toByteArray());

        if(type == CEntryField::Image)
        {
                QPixmap pix;
                pix.loadFromData(decrypt);

                if(!pix.isNull())
                {
                    QByteArray tmp;

                    QBuffer buf(&tmp);
                    buf.open(QIODevice::WriteOnly);

                    pix.save(&buf, "PNG");
                    buf.close();

                    return tmp;
                }
                else
                {
                    return decrypt;
                }
        }
        else
        {
            if(type==CEntryField::Password || type==CEntryField::Text || type==CEntryField::Url)
                return QString::fromUtf8(decrypt);
            else
                return decrypt;
        }
    #endif
}

QString CEntryField::md5()
{
    if(type!=this->File)
        return QString();

    if(m_md5.isNull())
    {
        QCA::Hash md5("md5");
        QCA::SecureArray iv = md5.process(m_value.toByteArray());
        QByteArray key = iv.toByteArray().toHex();
        m_md5 = QString::fromLatin1(key);
    }

    return m_md5;
}
